﻿using System;
using System.Linq;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using FB2Library;
using FB2Library.Elements;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace FbHelperWP7NonUi.TextHelpers
{
    internal sealed class Fb2Book : Book
    {
        private Fb2Book( string title, ReadOnlyCollection<Human> authors, ReadOnlyCollection<AbstractTextPart> text )
            : base( title, authors, text )
        {

        }

        public static Fb2Book Open( Stream inputStream )
        {
            using (XmlReader reader = XmlReader.Create( inputStream ))
            {
                XDocument fb2Document = XDocument.Load( reader, LoadOptions.PreserveWhitespace );

                FB2File file = new FB2File();

                file.Load( fb2Document, false );

                List<AbstractTextPart> result = new List<AbstractTextPart>();

                foreach (BodyItem bodyItem in file.Bodies)
                {
                    foreach (SectionItem secionItem in bodyItem.Sections)
                        AppendSectionItem( secionItem, 0, result );
                }

#warning Check for nulls
                ReadOnlyCollection<Human> authors = file.TitleInfo.BookAuthors
                    .Select( author => new Human( author.FirstName.Text + author.LastName.Text ) )
                    .ToList().AsReadOnly();


                return new Fb2Book( file.TitleInfo.BookTitle.Text, authors, result.AsReadOnly() );
            }
        }

        private static void AppendSectionItem( SectionItem item, int itemDepth, List<AbstractTextPart> appendTo )
        {
            List<AbstractTextPart> titleText = new List<AbstractTextPart>();

            foreach (IFb2TextItem iTextItem in item.Title.TitleData)
                AppendIFb2TextItem( iTextItem, itemDepth + 1, titleText );

            string headingText = titleText.Select( part => part.CreateTextVisual().Text ).Aggregate( ( left, right ) => left + ' ' + right );

            headingText = headingText.Split( new[] { ' ', '\n' } ).Aggregate( ( left, right ) => left + right );

            appendTo.Add( new Heading( itemDepth, headingText ) );

            foreach (IFb2TextItem textItem in item.SubSections)
            {
                SectionItem sectionItem = textItem as SectionItem;

                if (sectionItem != null)
                {
                    AppendSectionItem( sectionItem, itemDepth + 1, appendTo );

                    continue;
                }

                throw new NotImplementedException();
            }

            foreach (IFb2TextItem content in item.Content)
            {
                if (content is SectionItem)
                {
                    AppendSectionItem( content as SectionItem, itemDepth + 1, appendTo );

                    continue;
                }

                if (content is ParagraphItem)
                {
                    ParagraphItem paragraph = content as ParagraphItem;

                    foreach (StyleType styleType in paragraph.ParagraphData)
                    {
                        AppendStyleType( styleType, appendTo );
                    }

                    continue;
                }

                if (content is EmptyLineItem)
                {
                    appendTo.Add( SimpleText.EmptyParagraph );

                    continue;
                }

                throw new NotImplementedException();
            }
        }

        private static void AppendIFb2TextItem( IFb2TextItem item, int depth, List<AbstractTextPart> appendTo )
        {
            SectionItem sectionItem = item as SectionItem;

            if (sectionItem != null)
            {
                AppendSectionItem( sectionItem, depth + 1, appendTo );

                return;
            }

            ParagraphItem paragraphItem = item as ParagraphItem;

            if (paragraphItem != null)
            {
                AppendParagraphItem( appendTo, paragraphItem );

                return;
            }

            if (item is EmptyLineItem)
            {
                appendTo.Add( SimpleText.EmptyParagraph );

                return;
            }

            throw new NotImplementedException();
        }

        private static void AppendParagraphItem( List<AbstractTextPart> appendTo, ParagraphItem paragraphItem )
        {
            foreach (StyleType styleType in paragraphItem.ParagraphData)
            {
                AppendStyleType( styleType, appendTo );
            }
        }

        private static void AppendStyleType( StyleType styleType, List<AbstractTextPart> appendTo )
        {
            FB2Library.Elements.SimpleText simpleText = styleType as FB2Library.Elements.SimpleText;

            if (simpleText != null)
            {
                appendTo.Add( new SimpleText( simpleText.Text ) );

                foreach (StyleType subType in simpleText.Children)
                    AppendStyleType( subType, appendTo );

                return;
            }

            throw new NotImplementedException();
        }

    }
}
